// Example demonstrating network optimization features
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/smart-snapshotter/internal/logging"
	"github.com/smart-snapshotter/pkg/network"
)

func main() {
	// Initialize logger
	logger := logging.NewLogger(logging.Config{
		Level:  "info",
		Format: "json",
		Output: "stdout",
	})

	// Create network optimizer configuration
	config := network.DefaultConfig()

	// Customize configuration
	config.DownloadManager.MaxParallelDownloads = 10
	config.DownloadManager.BandwidthLimit = 1024 * 1024 * 5 // 5MB/s limit
	config.DownloadManager.ResumeEnabled = true
	config.DownloadManager.VerifyChecksum = true
	config.ParallelDownload.MaxConnections = 8
	config.ParallelDownload.ChunkSize = 2 * 1024 * 1024 // 2MB chunks

	// Create network optimizer
	optimizer, err := network.NewNetworkOptimizer(config, logger)
	if err != nil {
		log.Fatalf("Failed to create network optimizer: %v", err)
	}

	// Start the optimizer
	if err := optimizer.Start(); err != nil {
		log.Fatalf("Failed to start network optimizer: %v", err)
	}
	defer optimizer.Stop()

	fmt.Println("Network optimizer started successfully")

	// Example 1: Basic file download
	fmt.Println("\n=== Example 1: Basic File Download ===")
	basicDownloadExample(optimizer)

	// Example 2: Parallel download with progress monitoring
	fmt.Println("\n=== Example 2: Parallel Download with Progress ===")
	parallelDownloadExample(optimizer)

	// Example 3: Download with bandwidth limiting
	fmt.Println("\n=== Example 3: Bandwidth Limited Download ===")
	bandwidthLimitExample(optimizer)

	// Example 4: Download resume functionality
	fmt.Println("\n=== Example 4: Download Resume ===")
	resumeDownloadExample(optimizer)

	// Example 5: Multiple concurrent downloads
	fmt.Println("\n=== Example 5: Multiple Concurrent Downloads ===")
	concurrentDownloadsExample(optimizer)

	// Display final statistics
	fmt.Println("\n=== Final Statistics ===")
	stats := optimizer.GetNetworkStats()
	fmt.Printf("Total Downloads: %d\n", stats.TotalDownloads)
	fmt.Printf("Completed Downloads: %d\n", stats.CompletedDownloads)
	fmt.Printf("Failed Downloads: %d\n", stats.FailedDownloads)
	fmt.Printf("Total Bytes Downloaded: %d\n", stats.DownloadedBytes)
	fmt.Printf("Average Speed: %d bytes/sec\n", stats.AverageSpeed)
}

func basicDownloadExample(optimizer *network.NetworkOptimizer) {
	// URL and file path (using a real example URL)
	url := "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
	filePath := "/tmp/dummy.pdf"

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	fmt.Printf("Downloading %s to %s...\n", url, filePath)

	start := time.Now()
	download, err := optimizer.DownloadFile(ctx, url, filePath, "")
	if err != nil {
		fmt.Printf("Download failed: %v\n", err)
		return
	}

	// Wait for completion
	if err := waitForDownload(optimizer, download.ID, 30*time.Second); err != nil {
		fmt.Printf("Download failed: %v\n", err)
		return
	}

	elapsed := time.Since(start)
	fmt.Printf("Download completed in %v\n", elapsed)

	// Verify file exists
	if info, err := os.Stat(filePath); err == nil {
		fmt.Printf("File size: %d bytes\n", info.Size())
	}
}

func parallelDownloadExample(optimizer *network.NetworkOptimizer) {
	url := "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
	filePath := "/tmp/dummy_parallel.pdf"

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	fmt.Printf("Starting parallel download of %s...\n", url)

	download, err := optimizer.DownloadFile(ctx, url, filePath, "")
	if err != nil {
		fmt.Printf("Download failed: %v\n", err)
		return
	}

	// Monitor progress
	ticker := time.NewTicker(500 * time.Millisecond)
	defer ticker.Stop()

	start := time.Now()
	for {
		select {
		case <-ticker.C:
			progress, err := optimizer.GetDownloadProgress(download.ID)
			if err != nil {
				fmt.Printf("Failed to get progress: %v\n", err)
				continue
			}

			switch progress.Status {
			case "completed":
				elapsed := time.Since(start)
				fmt.Printf("\nDownload completed in %v\n", elapsed)
				fmt.Printf("Average speed: %.2f KB/s\n", float64(progress.BytesDownloaded)/elapsed.Seconds()/1024)
				return
			case "failed":
				fmt.Printf("\nDownload failed: %v\n", progress.Error)
				return
			case "downloading":
				percentage := float64(progress.BytesDownloaded) / float64(progress.BytesTotal) * 100
				speed := float64(progress.Speed) / 1024
				fmt.Printf("\rProgress: %.1f%%, Speed: %.1f KB/s, ETA: %v",
					percentage, speed, progress.ETA)
			}
		case <-time.After(30 * time.Second):
			fmt.Println("\nDownload timeout")
			return
		}
	}
}

func bandwidthLimitExample(optimizer *network.NetworkOptimizer) {
	// Set bandwidth limit to 1MB/s
	optimizer.SetBandwidthLimit(1024 * 1024)
	fmt.Println("Bandwidth limit set to 1MB/s")

	url := "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
	filePath := "/tmp/dummy_limited.pdf"

	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	fmt.Printf("Starting bandwidth-limited download of %s...\n", url)

	start := time.Now()
	download, err := optimizer.DownloadFile(ctx, url, filePath, "")
	if err != nil {
		fmt.Printf("Download failed: %v\n", err)
		return
	}

	if err := waitForDownload(optimizer, download.ID, 60*time.Second); err != nil {
		fmt.Printf("Download failed: %v\n", err)
		return
	}

	elapsed := time.Since(start)
	fmt.Printf("Download completed in %v (should be slower due to bandwidth limit)\n", elapsed)

	// Remove bandwidth limit
	optimizer.SetBandwidthLimit(0)
	fmt.Println("Bandwidth limit removed")
}

func resumeDownloadExample(optimizer *network.NetworkOptimizer) {
	url := "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
	filePath := "/tmp/dummy_resume.pdf"

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	fmt.Printf("Starting download with resume capability: %s...\n", url)

	// Start download
	download, err := optimizer.DownloadFile(ctx, url, filePath, "")
	if err != nil {
		fmt.Printf("Download failed: %v\n", err)
		return
	}

	// Simulate interruption after 2 seconds
	go func() {
		time.Sleep(2 * time.Second)
		fmt.Println("\nSimulating network interruption...")
		optimizer.PauseDownload(download.ID)
		time.Sleep(1 * time.Second)
		fmt.Println("Resuming download...")
		optimizer.ResumeDownload(download.ID)
	}()

	if err := waitForDownload(optimizer, download.ID, 60*time.Second); err != nil {
		fmt.Printf("Download failed: %v\n", err)
		return
	}

	fmt.Println("Download with resume completed successfully")
}

func concurrentDownloadsExample(optimizer *network.NetworkOptimizer) {
	urls := []string{
		"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
		"https://sample-videos.com/zip/10mb.zip",
		"https://sample-videos.com/zip/5mb.zip",
	}

	filePaths := []string{
		"/tmp/concurrent_1.pdf",
		"/tmp/concurrent_2.zip",
		"/tmp/concurrent_3.zip",
	}

	fmt.Printf("Starting %d concurrent downloads...\n", len(urls))

	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	var downloads []*network.Download
	start := time.Now()

	// Start all downloads
	for i, url := range urls {
		download, err := optimizer.DownloadFile(ctx, url, filePaths[i], "")
		if err != nil {
			fmt.Printf("Failed to start download %d: %v\n", i+1, err)
			continue
		}
		downloads = append(downloads, download)
		fmt.Printf("Started download %d: %s\n", i+1, url)
	}

	// Wait for all downloads to complete
	var wg sync.WaitGroup
	for i, download := range downloads {
		wg.Add(1)
		go func(idx int, dl *network.Download) {
			defer wg.Done()
			if err := waitForDownload(optimizer, dl.ID, 60*time.Second); err != nil {
				fmt.Printf("Download %d failed: %v\n", idx+1, err)
			} else {
				fmt.Printf("Download %d completed\n", idx+1)
			}
		}(i, download)
	}

	wg.Wait()
	elapsed := time.Since(start)

	fmt.Printf("All downloads completed in %v\n", elapsed)

	// Verify files
	for i, filePath := range filePaths {
		if info, err := os.Stat(filePath); err == nil {
			fmt.Printf("File %d: %s (size: %d bytes)\n", i+1, filePath, info.Size())
		}
	}
}

// Helper function to wait for download completion
func waitForDownload(optimizer *network.NetworkOptimizer, downloadID string, timeout time.Duration) error {
	deadline := time.Now().Add(timeout)
	ticker := time.NewTicker(500 * time.Millisecond)
	defer ticker.Stop()

	for time.Now().Before(deadline) {
		progress, err := optimizer.GetDownloadProgress(downloadID)
		if err != nil {
			return err
		}

		switch progress.Status {
		case "completed":
			return nil
		case "failed":
			return progress.Error
		case "cancelled":
			return fmt.Errorf("download was cancelled")
		}

		<-ticker.C
	}

	return fmt.Errorf("download timeout")
}